#include "../Global/GlobalDefs.hpp"
#ifdef NTC_TEMP_SENSOR
// ADS1115_WE from Arduino Lib by Wolfgang...
#include "tempUpdate.hpp"
#include "../Global/globalVars.hpp"
#include "ADS1115_WE/ADS1115_WE.h"
#include <arduino.h>
#include "Wire.h"
//#include <Wire.h>
// #include "esp_adc_cal.h"

#define I2C_ADDRESS 0x48
#define plateTmpCaliParaIdx 0
#define plateTmpChannel ADS1115_COMP_0_GND
#define pumpTmpCaliParaIdx 1
#define pumpTmpChannel ADS1115_COMP_1_GND
#define containerTmpCaliParaIdx 2
#define containerTmpChannel ADS1115_COMP_2_GND
#define surroundingTmpCaliParaIdx 3
#define surroundingTmpChannel ADS1115_COMP_3_GND
#define MAX_UPDATE_WAIT_MS 50
#define PLATE_TEMP_CALI_PT_NUM_MAX 16

int timeOutOnRead = 0;

float PLATE_TEMP_CALI_TEMP_KS[PLATE_TEMP_CALI_PT_NUM_MAX] = { 0 };
float PLATE_TEMP_CALI_VOLT_MVS[PLATE_TEMP_CALI_PT_NUM_MAX] = { 0 };
float lidNTCB;
float lidNTCRefR;
float surroundingNTCB;
float surroundingNTCRefR;
float Temp;

ADS1115_MUX currentChannel = surroundingTmpChannel; // ok  ADS1115_MUX currentChannel?
ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS);           // I2C_ADDRESS 0x48,创建ADS1115_WE对象
uint8_t adcState = 0;
// WEok   ADS1115_用法

bool initADCIfNeeded() {
	if (adcState > 0) {
		return true;
	}
	bool ret = adc.init();
	if (ret)
	{
		adc.setConvRate(ADS1115_250_SPS);           // sps=250 -> effective reso for range 4096: 15.75
		adc.setVoltageRange_mV(ADS1115_RANGE_4096); //
		adc.setMeasureMode(ADS1115_SINGLE);         //
		adc.setCompareChannels(currentChannel);     //
		
		adcState = 1;
		return true;
	}
	else {
		return false;
	}
	
}

float voltageFromAdc(ADS1115_MUX channel) // ok   ADS1115_MUX channel?
{
	if (!initADCIfNeeded()) {
		return ERROR_TEMP_READ_TIMEOUT;
	}
	int startTime = millis();

	if (currentChannel != channel)
	{
		adc.setCompareChannels(channel); // ok  adc.setCompareChannels?哪里来的,设置要比较的通道
		currentChannel = channel;
	}

	//Serial.print("Set channel");
	//Serial.println(millis() - startTime);
	//startTime = millis();

	adc.startSingleMeasurement(); //开始对以前使用 选择的通道进行转换

	//Serial.print("start single taken");
	//Serial.println(millis() - startTime);
	//startTime = millis();

	delay(6);                     // 250 sps
	startTime = millis();
	while (millis() - startTime < MAX_UPDATE_WAIT_MS)
	{
		if (adc.isBusy()) //在转换尚未完成时返回 true
		{
			delay(1);
		}
		else
		{
			//Serial.print("Wait until ready");
			//Serial.println(millis() - startTime);
			//startTime = millis();

			float mv = adc.getResult_mV(); // getResult_V()以伏特为单位提供电压。对于较小的值，您可以使�? .getResult_mV()
			return mv;
		}
	}

	//Serial.print("Loop until timeout");
	//Serial.println(millis() - startTime);
	//startTime = millis();

	adcState = 0;

	return ERROR_TEMP_READ_TIMEOUT;
}

float voltMV2tmp(float voltageMV, int channel, bool flagVerbose = false)
{

	// NTC: 100k; divider: 47k(low temp drift)
	//const float Rp = 100000.0; // 100K
	const float Rp = 10000.0; // 10K, on Mount board
	//const float Rdiv = 47000.0;
	const float Rdiv = 4700.0; // 4.7k, R_NTCn on ADC board
	//const float Bx = 4250.0;          // B for 100k
	const float Bx = 3950;          // B for 10k
	const float Ka = 273.15;          // K
	const float T2 = (Ka + 25.0); // T2, NTC reference temp
	const float ov = 3300.0;
	float Rt = (Rdiv * voltageMV) / (ov - voltageMV);
	float firstPart = log(Rt / Rp) / Bx;
	const float secondPart = (1 / T2);
	Temp = 1 / (firstPart + secondPart) - Ka; // ok上面计算原理?NTC原理

	if (ov <= voltageMV || Temp < TEMP_VALID_MIN || Temp > TEMP_VALID_MAX)
	{
#ifdef DEBUG_LOG // no ,continue
		flagVerbose = true;
#endif
		Temp = ERROR_TEMP_CONVERSION_INVALID;
	}
	if (flagVerbose)
	{
		Serial.print("Temp=" + String(Temp));
		Serial.print(", Volt=" + String(voltageMV) + ", Rt=" + String(Rt));
		Serial.println(", firstPart=" + String(firstPart) + ", secondPart=" + String(secondPart));
	}
	return Temp;
}

bool TempReader::init()
{
	Wire.begin(TEMP_ADC_SDA, TEMP_ADC_SCL);
	bool ret = initADCIfNeeded();

	pinMode(INTERNAL_TEMP_ADC_PIN, INPUT);
	analogSetPinAttenuation(INTERNAL_TEMP_ADC_PIN, ADC_11db); //

	return ret;
}

float plateTmpBuf = ERROR_TEMP_READ_TIMEOUT;
float TempReader::readPlateTmp(bool flagVerbose)
{
	const float updateRatio = 0.1;
	float mv = voltageFromAdc(plateTmpChannel); //
	if (mv == ERROR_TEMP_READ_TIMEOUT)          //
	{
		return ERROR_TEMP_READ_TIMEOUT;
	}
	else
	{
		if (plateTmpBuf == ERROR_TEMP_READ_TIMEOUT)
		{
			plateTmpBuf = mv;
		}
		else
		{
			plateTmpBuf = plateTmpBuf * (1 - updateRatio) + mv * updateRatio;
		}
		return voltMV2tmp(plateTmpBuf, plateTmpCaliParaIdx, flagVerbose);
	}
	return ERROR_TEMP_READ_TIMEOUT;
}

float pumpTmpBuf = ERROR_TEMP_READ_TIMEOUT;
float TempReader::readPumpTmp(bool flagVerbose)
{
	const float updateRatio = 0.1;
	float mv = voltageFromAdc(pumpTmpChannel); //
	if (mv == ERROR_TEMP_READ_TIMEOUT)          //
	{
		return ERROR_TEMP_READ_TIMEOUT;
	}
	else
	{
		if (pumpTmpBuf == ERROR_TEMP_READ_TIMEOUT)
		{
			pumpTmpBuf = mv;
		}
		else
		{
			pumpTmpBuf = pumpTmpBuf * (1 - updateRatio) + mv * updateRatio;
		}
		return voltMV2tmp(pumpTmpBuf, pumpTmpCaliParaIdx, flagVerbose);
	}
	return ERROR_TEMP_READ_TIMEOUT;
}

float containerTmpBuf = ERROR_TEMP_READ_TIMEOUT;
float TempReader::readContainerTmp(bool flagVerbose)
{
	const float updateRatio = 0.3;
	float mv = voltageFromAdc(containerTmpChannel);
	if (mv == ERROR_TEMP_READ_TIMEOUT)
	{
		return ERROR_TEMP_READ_TIMEOUT;
	}
	else
	{
		if (containerTmpBuf == ERROR_TEMP_READ_TIMEOUT)
		{
			containerTmpBuf = mv;
		}
		else
		{
			containerTmpBuf = containerTmpBuf * (1 - updateRatio) + mv * updateRatio;
		}
		return voltMV2tmp(containerTmpBuf, containerTmpChannel, flagVerbose);
	}

	return ERROR_TEMP_READ_TIMEOUT;
}

float TempReader::readSurroundingTmp(bool flagVerbose)
{
	float mv = voltageFromAdc(surroundingTmpChannel);
	if (mv == ERROR_TEMP_READ_TIMEOUT)
	{
		return ERROR_TEMP_READ_TIMEOUT;
	}
	else
	{
		return voltMV2tmp(mv, surroundingTmpCaliParaIdx, flagVerbose);
	}

	return ERROR_TEMP_READ_TIMEOUT;
}

float internalVoltBuf = ERROR_TEMP_READ_TIMEOUT;
float TempReader::readInternalTmp(bool flagVerbose)
{
	const float updateRatio = 0.3;
	// https://docs.espressif.com/projects/arduino-esp32/en/latest/api/adc.html
	// https://github.com/espressif/arduino-esp32/issues/4941
	// "CircuitPython uses the SDK to set gain to -11dB but I calculated the actual value as -7.5dB based on the ADC being unable to go above 2.6V."
	// float correctionFactorC3 = 1.5;
	// float mv = analogReadMilliVolts(INTERNAL_TEMP_ADC_PIN) * correctionFactorC3;
	float mv = analogReadMilliVolts(INTERNAL_TEMP_ADC_PIN);
	//Serial.println("readInternalTmp");
	//Serial.println(mv);
	if (internalVoltBuf == ERROR_TEMP_READ_TIMEOUT)
	{
		internalVoltBuf = mv;
	}
	else
	{
		internalVoltBuf = internalVoltBuf * (1 - updateRatio) + mv * updateRatio;
	}

	float ret = voltMV2tmp(internalVoltBuf, -1, flagVerbose);
	//Serial.println(ret);
	return ret;
}

int TempReader::setPlateTmpCaliTmpKs(float* tmpKs, int num)
{
	num = min(num, PLATE_TEMP_CALI_PT_NUM_MAX);
	memcpy(PLATE_TEMP_CALI_TEMP_KS, tmpKs, num * sizeof(float));
	int residue = sizeof(PLATE_TEMP_CALI_TEMP_KS) - num;
	if (residue > 0)
	{
		memset(PLATE_TEMP_CALI_TEMP_KS + num, 0, sizeof(float) * residue);
	}
	return num;
}

int TempReader::setPlateTmpCaliVolts(float* voltMvs, int num)
{
	num = min(num, PLATE_TEMP_CALI_PT_NUM_MAX);
	memcpy(PLATE_TEMP_CALI_VOLT_MVS, voltMvs, num * sizeof(float));
	int residue = sizeof(PLATE_TEMP_CALI_TEMP_KS) - num;
	if (residue > 0)
	{
		memset(PLATE_TEMP_CALI_VOLT_MVS + num, 0, sizeof(float) * residue);
	}
	return num;
}

void TempReader::setLidTmpNTCBR(float ntcBVal, float referenceR)
{
	lidNTCB = ntcBVal;
	lidNTCRefR = referenceR;
}

void TempReader::setSurroundingTmpNTCBR(float ntcBVal, float referenceR)
{
	surroundingNTCB = ntcBVal;
	surroundingNTCRefR = referenceR;
}

float TempReader::readSampleLeftTmp(bool flagVerbose) {
	return ERROR_TEMP_NOT_DEFINED;
}

float TempReader::readSampleRightTmp(bool flagVerbose) {
	return ERROR_TEMP_NOT_DEFINED;
}

#endif
